<?php
namespace App\Services\Goods;
use App\Common\BnFormatConfig;
use App\Common\ResponseCode;
use App\Common\Tools;
use App\Exceptions\BusinessException;
use App\Common\Constant;
use App\Entity\OpResult;
use App\Models\Common\Tag;
use App\Models\Goods\Brand;
use App\Models\Goods\Comment;
use App\Models\Goods\Goods;
use App\Models\Goods\Specs;
use App\Models\Goods\Products;
use App\Models\Goods\SpecValue;
use App\Params\Backend\BrandListParams;
use App\Params\Backend\GoodsListParams;
use App\Params\Backend\GoodsUpdateParam;
use App\Params\Backend\TagListParams;
use App\Params\H5\CommentListParams;
use App\Repository\GoodsRepository;
use App\Services\BaseService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use mysql_xdevapi\Exception;

/**
 * 商品相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services
 */
class GoodsService extends BaseService
{
    /**
     * 货品列表
     *
     * @param GoodsListParams $params
     * @return array
     */
    public function getList(GoodsListParams $params)
    {
        $result = GoodsRepository::getInstance()->getList($params);
        $result = $this->toList($result, $params->getPage(), $params->getPageSize());
        foreach ($result['list'] as $item) {
            $item->goods_id = (string)$item->goods_id;
        }
        return $result;
    }

    /**
     * 获取商品信息
     *
     * @param int $goodsId
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws BusinessException
     */
    public function get(int $goodsId)
    {
        return GoodsRepository::getInstance()->getById($goodsId);
    }

    /**
     * 新增商品
     *
     * @param GoodsUpdateParam $param
     * @return int
     * @throws BusinessException
     */
    public function create(GoodsUpdateParam $param)
    {
        $param->setGoodsId(Tools::nextId());
        $param->setGoodsBn(Tools::buildBn(BnFormatConfig::GOODS_BN_KEY));
        // 校验商品名称
        if(Goods::checkName($param->getName(), $param->getGoodsId())) {
            throw new BusinessException(ResponseCode::GOODS_SAVE_FAIL, ['error' => '商品名称(' . $param->getName() . ')已存在']);
        }
        try {
            DB::beginTransaction();
            // 处理分类path
            $param->category_ids = $param->getCategoryId();
            $param->setCategoryId(last($param->getCategoryId()));

            // 取出规格信息并删除原对象值
            $specKeyList = $param->getSpecKeyListStr();
            $specValueList = $param->getSpecListStr();
            unset($param->spec_list_str, $param->spec_key_list_str);

            // 保存货品信息
            $goodsId = GoodsRepository::getInstance()->saveData($param);
            if(empty($goodsId)) {
                throw new \Exception('保存货品失败');
            }

            // 处理规格
            $this->saveSpec($param->getGoodsId(), $specKeyList);

            // 处理商品
            $this->saveProduct($param->getGoodsId(), $specValueList);
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            throw new BusinessException(ResponseCode::GOODS_SAVE_FAIL, ['error' => $exception->getMessage()]);
        }
        return $param->getGoodsId();
    }

    /**
     * 保存商品信息
     *
     * @param GoodsUpdateParam $data
     * @return OpResult
     * @throws BusinessException
     */
    public function update(GoodsUpdateParam $data)
    {
        $opResult = OpResult::create();
        try {
            // 开启事务
            DB::beginTransaction();
            // 处理主商品
            // 校验商品名称
            if(Goods::checkName($data->getName(), $data->getGoodsId())) {
                throw new \Exception('商品名称(' . $data['name'] . ')已存在');
            }

            // 处理分类path
            $data->category_ids = $data->getCategoryId();
            $data->setCategoryId(last($data->getCategoryId()));

            // 取出规格信息并删除原对象值
            $specKeyList = $data->getSpecKeyListStr();
            $specValueList = $data->getSpecListStr();
            unset($data->spec_list_str, $data->spec_key_list_str);

            // 保存货品信息
            $goodsId = GoodsRepository::getInstance()->saveData($data, $data->getGoodsId());
            if(empty($goodsId)) {
                throw new \Exception('保存货品失败');
            }

            // 处理规格
            $this->saveSpec($data->getGoodsId(), $specKeyList);

            // 处理商品
            $this->saveProduct($data->getGoodsId(), $specValueList);
            DB::commit();
            $opResult->setCode(1)->setData($data->getGoodsId())->setMessage('保存成功');
        } catch (\Exception $exception) {
            DB::rollBack();
            $opResult->setMessage($exception->getMessage());
            Log::error('[保存商品] 出错' . $exception->getMessage() . $exception->getFile());
        }
        return $opResult;
    }

    /**
     * 获取保存商品的初始化数据
     *
     * @return mixed
     */
    public function getInitData()
    {
        // 获取品牌
        $param = new BrandListParams();
        $param->setIsActive(1);
        $result['brand_list'] = Brand::getByFilter($param)->get();
        // 获取分类（含父子关系）
        $result['category_list'] = CategoryService::getInstance()->getBackendSelectTree();
        // 标签列表
        $param = new TagListParams();
        $param->setIsActive(1);
        $param->setType('GOODS');
        $result['tag_list'] = Tag::getByFilter($param)->get();
        // 发布平台
        $result['platform'] = Constant::GOODS_PLATFORM_MAP;
        return $result;
    }

    /**
     * 保存规格
     *
     * @param int $goodsId
     * @param array $specs
     * @throws
     */
    public function saveSpec(int $goodsId, array $specs)
    {
        try {
            DB::beginTransaction();
            foreach ($specs as $spec)
            {
                $spec['goods_id'] = $goodsId;
                $specId = Specs::saveData($spec);
                if(empty($specId)) {
                    throw new \Exception('保存规格失败');
                }
                // 保存规格的值
                $valueId = SpecValue::saveData($specId, $spec['values']);
                if(empty($valueId)) {
                    throw new \Exception('保存规格值失败');
                }
            }
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            throw new BusinessException(ResponseCode::SAVE_FAIL, ['error' => $exception->getMessage()]);
        }
    }

    /**
     * 保存商品
     *
     * @param int $productId
     * @param int $goodsId
     * @param array $specKey
     * @param array $specValue
     * @throws
     */
    public function saveProduct(int $goodsId, array $specValue = [])
    {
        // 遍历规格
        foreach ($specValue as $spec)
        {
            $spec['goods_id'] = $goodsId;
            // 根据规格值获取规格值的 Id
            $specList = explode(';', $spec['specs']);
            $specIds = collect($specList)->map(function ($item) use ($goodsId) {
                return SpecValue::getByGoodsIdAndVal($goodsId, $item);
            })->toArray();
            $spec['spec_ids'] = $specIds;
            $productId = Products::saveData($spec);
            if(empty($productId)) {
                throw new \Exception('保存商品失败');
            }
        }
    }

    /**
     * 商品列表（H5）
     *
     * @param \App\Params\H5\GoodsListParams $params
     * @return array
     */
    public function getH5GoodsList(\App\Params\H5\GoodsListParams $params)
    {
        $goods = Goods::getList($params);
        $goods = $this->toList($goods, $params->getPage(), $params->getPageSize());
        foreach ($goods['list'] as $good) {
            $good->goods_id = (string)$good->goods_id;
        }
        return $goods;
    }

    /**
     * 商品详情（H5）
     *
     * @param int $goodsId
     * @param int $customerId
     * @throws
     * @return
     */
    public function getH5Goods(int $goodsId, int $customerId = 0)
    {
        $columns = ['a.goods_id', 'a.name','a.gallery','a.sold_num','a.tag_ids','a.video_url','a.pc_detail','a.market_price','a.goods_bn','a.intro','a.sales_price'];
        return GoodsRepository::getInstance()->getById($goodsId, $columns);
    }

    /**
     * 获取商品评论列表
     *
     * @param CommentListParams $param
     * @return array
     */
    public function getCommentList(CommentListParams $param)
    {
        $comment = GoodsRepository::getInstance()->getCommentList($param->toArray());
        return $this->toList($comment, $param->getPage(), $param->getPageSize());
    }

    /**
     * 获取商品服务列表
     *
     * @param int $goodsId
     * @return array
     */
    public function getServiceList(int $goodsId = 0)
    {
        $data = [
            [
                'name' => '七天无理由退货',
                'summary' => '满足相应条件时，消费者可申请7天无理由退货'
            ],
            [
                'name' => '48小时发货',
                'summary' => '下单后48小时之内发货'
            ]
        ];
        return $data;
    }

    /**
     * 获取商品评论统计
     *
     * @param int $goodsId
     * @return mixed
     */
    public function getCommentStat(int $goodsId)
    {
        $filter = ['goods_id' => $goodsId];
        $stat = ['all' => 0, 'praise' => 0, 'review' => 0, 'negative' => 0];
        $comment = GoodsRepository::getInstance()->getCommentList($filter)->get();
        $stat['all'] = $comment->count();
        collect($comment)->each(function ($item) use (&$stat) {
            if($item->score == 10) {
                $stat['praise'] += 1;
            }
            if($item->score == 20) {
                $stat['review'] += 1;
            }
            if($item->score == 30) {
                $stat['negative'] += 1;
            }
        });
        return $stat;
    }

    /**
     * 统计商品数量
     *
     * @return int
     */
    public function getCount()
    {
        return GoodsRepository::getInstance()->getCountNum();
    }
}
